// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#include <dlfcn.h>
#include <iostream>
#include <pollux/common/base/exceptions.h>
#include <pollux/functions/dynamic_library_loader.h>
#include <pollux/expression/simple_function_registry.h>

namespace kumo::pollux {
    static constexpr const char *kSymbolName = "registry";

    turbo::Status load_dynamic_library(const std::string &fileName) {
        // Try to dynamically load the shared library.
        void *handler = dlopen(fileName.c_str(), RTLD_GLOBAL | RTLD_NOW);

        if (handler == nullptr) {
            return turbo::unavailable_error("Error while loading shared library: ", dlerror());
        }

        KLOG(INFO) << "Loaded library " << fileName << ". Searching registry symbol "
                << kSymbolName;
        // Lookup the symbol.
        void *registrySymbol = dlsym(handler, kSymbolName);
        auto loadUserLibrary = reinterpret_cast<void (*)()>(registrySymbol);
        const char *error = dlerror();

        // Check for an error first as a null symbol pointer is not necessarily an
        // error.
        if (error != nullptr) {
            return turbo::unavailable_error("Couldn't find Pollux registry symbol: ", error);
        }

        if (loadUserLibrary == nullptr) {
            return turbo::unavailable_error(
                "Symbol '", kSymbolName, "' resolved to a nullptr, unable to invoke it.");
        }

        // Invoke the registry function.
        KLOG(INFO) << "Found registry function. Invoking it.";
        loadUserLibrary();
        KLOG(INFO) << "Registration complete.";
        return turbo::OkStatus();
    }
} // namespace kumo::pollux
